#!/bin/bash
############################################################################
#                                                                          #
# This file is part of the IPFire Firewall.                                #
#                                                                          #
# IPFire is free software; you can redistribute it and/or modify           #
# it under the terms of the GNU General Public License as published by     #
# the Free Software Foundation; either version 2 of the License, or        #
# (at your option) any later version.                                      #
#                                                                          #
# IPFire is distributed in the hope that it will be useful,                #
# but WITHOUT ANY WARRANTY; without even the implied warranty of           #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            #
# GNU General Public License for more details.                             #
#                                                                          #
# You should have received a copy of the GNU General Public License        #
# along with IPFire; if not, write to the Free Software                    #
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA #
#                                                                          #
# Copyright (C) 2016 IPFire Team <info@ipfire.org>                         #
#                                                                          #
############################################################################

[ -n "${INTERFACE}" ] || exit 2

eval $(/usr/local/bin/readhash /var/ipfire/ethernet/settings)

detect_zone() {
	local intf="${INTERFACE%?}"
	intf="${intf%phys}"
	intf="${intf^^}"

	local zone
	for zone in GREEN BLUE ORANGE RED; do
		# Try to find if INTERFACE is the *phys version of a zone
		if [ "${intf}" = "${zone}" ]; then
			echo "${zone}"
			return 0
		fi

		# Try to find out if this INTERFACE is a slave of a zone
		local slave
		for slave in $(get_value "${zone}_SLAVES"); do
			# Compare if the mac address matches or if the name matches
			if [ "$(cat /sys/class/net/${INTERFACE}/address 2>/dev/null)" = "${slave}" ] || [ "${INTERFACE}" = "${slave}" ]; then
				echo "${zone}"
				return 0
			fi
		done
	done

	return 1
}

get_value() {
	echo "${!1}"
}

random_mac_address() {
	local address="02"

	for i in $(seq 5); do
		printf -v address "${address}:%02x" "$(( RANDOM % 256 ))"
	done

	echo "${address}"
}

# Try to detect which zone we are operating on
ZONE=$(detect_zone)

# Cannot proceed if we could not find a zone
if [ -z "${ZONE}" ]; then
	logger "Could not find a bridged zone for ${INTERFACE}"
	exit 0
fi

# Determine the mode of this zone
MODE="$(get_value "${ZONE}_MODE")"

# The name of the virtual bridge
BRIDGE="$(get_value "${ZONE}_DEV")"
MTU="$(get_value "${ZONE}_MTU")"
STP="$(get_value "${ZONE}_STP")"
STP_PRIORITY="$(get_value "${ZONE}_STP_PRIORITY")"

case "${MODE}" in
	bridge)
		# Set default MTU if nothing is set
		if [ -z "${MTU}" ]; then
			MTU=1500
		fi

		# We need to check if $STP_PRIORITY has a valid value if not set it
		if [ -z "${STP_PRIORITY}" ]; then
			STP_PRIORITY=16384
		fi

		ADDRESS="$(get_value "${ZONE}_MACADDR")"
		[ -n "${ADDRESS}" ] || ADDRESS="$(random_mac_address)"

		# We need to create the bridge if it doesn't exist, yet
		if [ ! -d "/sys/class/net/${BRIDGE}" ]; then
			ip link add "${BRIDGE}" address "${ADDRESS}" mtu "${MTU}" type bridge \
				$([ "${STP}" = "on" ] && echo "stp_state 1  priority ${STP_PRIORITY}" )
			#ip link set "${BRIDGE}" up
		fi

		# Try setting wireless interfaces into master mode
		if [ -d "/sys/class/net/${INTERFACE}/phy80211" ]; then
			iw dev "${INTERFACE}" set type __ap
		fi

		# Attempt to set the MTU
		ip link set dev "${INTERFACE}" mtu "${MTU}"

		# Attach the physical device
		logger "Attach ${INTERFACE} to ${BRIDGE}"
		ip link set dev "${INTERFACE}" master "${BRIDGE}"
		ip link set dev "${INTERFACE}" up
		;;

	"")
		exit 0
		;;

	*)
		logger -t "network" "Unhandled mode '${MODE}' for '${ZONE}' (${INTERFACE})"
		exit 1
		;;
esac
